#ifndef INCLUDE_SHM_LOG_PRINTER_H
#define INCLUDE_SHM_LOG_PRINTER_H

#include <stdint.h>
#include <stdio.h>
#include "shm_log.h"

typedef struct shm_log_printer {
  bool running;
  shm_queue_t queue;
} shm_log_printer_t;

SHM_API int  shm_log_printer_init(shm_log_printer_t *printer,
    const char* config_file, const char* name);
SHM_API void shm_log_printer_deinit(shm_log_printer_t *printer);
SHM_API void shm_log_printer_run(shm_log_printer_t *printer);
SHM_API void shm_log_printer_stop(shm_log_printer_t *printer);

#endif //INCLUDE_SHM_LOG_PRINTER_H

#ifdef SHM_LOG_PRINTER_IMPLEMENTATION
#include "shm_ini.h"
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#define RESET "\033[0m\n"
#define BLACK "\033[30m"   /* Black */
#define RED "\033[31m"     /* Red */
#define GREEN "\033[32m"   /* Green */
#define YELLOW "\033[33m"  /* Yellow */
#define BLUE "\033[34m"    /* Blue */
#define MAGENTA "\033[35m" /* Magenta */
#define CYAN "\033[36m"    /* Cyan */
#define WHITE "\033[37m"   /* White */

struct shm_log_printer_config {
  const char *name;
  char shm_queue[SHM_LOG_MAX_NAME];
  uint32_t elem_size;
  uint32_t elem_count;
};

static int _shm_log_printer_ini_parse(
    void *user, const char *section, const char *name, const char *value) {
  struct shm_log_printer_config *config = (struct shm_log_printer_config *)user;
  if (strcmp(section, config->name) == 0) {
    if (strcmp(name, "shm_queue") == 0) {
      strncpy(config->shm_queue, value, SHM_LOG_MAX_NAME);
    } else if (strcmp(name, "elem_size") == 0) {
      config->elem_size = atoi(value);
    } else if (strcmp(name, "elem_count") == 0) {
      config->elem_count = atoi(value);
    }
  }
  return 0;
}


SHM_API int shm_log_printer_init(shm_log_printer_t *printer, 
    const char* config_file, const char* name) {
  int rslt;
  struct shm_log_printer_config config;
  FILE *file = fopen(config_file, "r");
  if (!file) {
    return SHM_QUEUE_ERROR_OPEN;
  }
  config.name = name;
  config.shm_queue[0] = '\0';
  config.elem_size = 1024;
  config.elem_count = 1024;
  ini_parse_file(file, _shm_log_printer_ini_parse, &config);
  fclose(file);

  shm_queue_options_t options;
  options.name = config.shm_queue;
  options.elem_count = config.elem_count;
  options.elem_size = config.elem_size;
  options.mode = SHM_QUEUE_MODE_READ | SHM_QUEUE_MODE_CREATE;
  return shm_queue_open(&printer->queue, &options);
}

SHM_API void shm_log_printer_deinit(shm_log_printer_t *printer) {
  shm_queue_close(&printer->queue);
}

SHM_API void shm_log_printer_run(shm_log_printer_t *printer) {
  void *data;
  uint32_t data_size;  
  printer->running = true;
  while (printer->running) {
    int rslt = shm_queue_ncread(&printer->queue, &data, &data_size);
    if (rslt == SHM_QUEUE_ERROR_OK) {
      const char* str = (const char*)data;
      switch (*str) {
        case 'I':
          printf(GREEN "%.*s" RESET, data_size, str);
          break;
        case 'W':
          printf(YELLOW "%.*s" RESET, data_size, str);
          break;
        case 'E':
          printf(RED "%.*s" RESET, data_size, str);
          break;
        case 'F':
          printf(RED "%.*s" RESET, data_size, str);
          break;
        default:
          printf("%.*s", data_size, str);
          break;         
      }
    } else {
      usleep(1000);
    }
  }
}

SHM_API void shm_log_printer_stop(shm_log_printer_t *printer) {
  printer->running = false;
}

#undef SHM_LOG_PRINTER_IMPLEMENTATION
#endif
